﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.DesignPattern.Observer;
using AAA.TradeLanguage.Data;

namespace AAA.TradeLanguage
{
    public sealed class SignalMonitor : ISubject
    {
        private static SignalMonitor _signalMonitor;

        private ISubject _subject;

        // Price, Signal-Side 
        private Dictionary<string, Dictionary<float, List<SignalInfo>>> _dicStopOrder;

        // Price, Signal-Side 
        private Dictionary<string, Dictionary<float, List<SignalInfo>>> _dicLimitOrder;

        // Price, Signal-Side 
        private Dictionary<string, Dictionary<float, List<SignalInfo>>> _dicMarketOrder;

        private SignalMonitor()       
        {
            _dicLimitOrder = new Dictionary<string, Dictionary<float, List<SignalInfo>>>();
            _dicStopOrder = new Dictionary<string, Dictionary<float, List<SignalInfo>>>();
            _dicMarketOrder = new Dictionary<string, Dictionary<float, List<SignalInfo>>>();
            _subject = new Subject();
        }

        public static SignalMonitor Instance
        {
            get
            {
                if (_signalMonitor == null)
                    _signalMonitor = new SignalMonitor();
                return _signalMonitor;
            }
        }
        
        public void AddActiveSignal(SignalInfo signalInfo)
        {
            List<SignalInfo> lstSignal;
            Dictionary<float, List<SignalInfo>> dicOrder = null;

            switch (signalInfo.OrderType)
            {
                case OrderTypeEnum.StopOrder:
                    dicOrder = _dicStopOrder[signalInfo.BaseSymbolId];
                    break;

                case OrderTypeEnum.LimitOrder:
                    dicOrder = _dicLimitOrder[signalInfo.BaseSymbolId];
                    break;

                case OrderTypeEnum.MarketOrder:
                    dicOrder = _dicMarketOrder[signalInfo.BaseSymbolId];
                    break;
            }

            if (dicOrder == null)
                return;

            if (dicOrder.ContainsKey(signalInfo.Price) == false)
            {
                lstSignal = new List<SignalInfo>();
                dicOrder.Add(signalInfo.Price, lstSignal);
            }
            else
            {
                lstSignal = dicOrder[signalInfo.Price];
            }
            lstSignal.Add(signalInfo);
        }        

        public void CancelOrder(string strBaseSymbol, string strSignal)
        {
            CancelOrder(strBaseSymbol, float.NaN, strSignal);
        }

        public void CancelOrder(string strBaseSymbolId, float fPrice, string strSignalName)
        {
            List<SignalInfo> lstSignal;

            if (float.IsNaN(fPrice) == false)
            {
                if (_dicStopOrder[strBaseSymbolId].ContainsKey(fPrice))
                {
                    lstSignal = _dicStopOrder[strBaseSymbolId][fPrice];
                    foreach (SignalInfo signalInfo in lstSignal)
                        if (signalInfo.SignalName == strSignalName)
                            lstSignal.Remove(signalInfo);
                }

                if (_dicLimitOrder[strBaseSymbolId].ContainsKey(fPrice))
                {
                    lstSignal = _dicLimitOrder[strBaseSymbolId][fPrice];
                    foreach (SignalInfo signalInfo in lstSignal)
                        if (signalInfo.SignalName == strSignalName)
                            lstSignal.Remove(signalInfo);

                }
            }
            else
            {
                foreach (float fKey in _dicStopOrder[strBaseSymbolId].Keys)
                {
                    if (_dicStopOrder[strBaseSymbolId].ContainsKey(fKey))
                    {
                        lstSignal = _dicStopOrder[strBaseSymbolId][fKey];
                        foreach (SignalInfo signalInfo in lstSignal)
                            if (signalInfo.SignalName == strSignalName)
                                lstSignal.Remove(signalInfo);
                    }
                }
                foreach (float fKey in _dicLimitOrder[strBaseSymbolId].Keys)
                {
                    if (_dicLimitOrder[strBaseSymbolId].ContainsKey(fKey))
                    {
                        lstSignal = _dicLimitOrder[strBaseSymbolId][fKey];
                        foreach (SignalInfo signalInfo in lstSignal)
                            if (signalInfo.SignalName == strSignalName)
                                lstSignal.Remove(signalInfo);
                    }
                }

            }

        }

        #region ISubject Members

        public void Attach(IObserver observer)
        {
            _subject.Attach(observer);
        }

        public void Detach(IObserver observer)
        {
            _subject.Detach(observer);
        }

        public void Notify(IMessageInfo miMessage)
        {
            _subject.Notify(miMessage);
        }

        #endregion
    }
}
